Visualizing PMTiles with Leafmap and MapLibre
PMTiles is a single-file archive format for tiled data. A PMTiles archive can be hosted on a commodity storage platform such as S3, and enables low-cost, zero-maintenance map applications that are "serverless" - free of a custom tile backend or third party provider.
In [1]:
Copied!
# %pip install -U "leafmap[maplibre]" pmtiles
# %pip install -U "leafmap[maplibre]" pmtiles
In [2]:
Copied!
import leafmap.maplibregl as leafmap
import leafmap.maplibregl as leafmap
In [3]:
Copied!
url = "https://open.gishub.org/data/pmtiles/protomaps_firenze.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
url = "https://open.gishub.org/data/pmtiles/protomaps_firenze.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
layer names: ['earth', 'natural', 'land', 'water', 'physical_line', 'buildings', 'physical_point', 'places', 'roads', 'transit', 'pois', 'boundaries', 'mask'] bounds: [11.154026, 43.7270125, 11.3289395, 43.8325455]
In [4]:
Copied!
m = leafmap.Map()
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "landuse",
"type": "fill",
"paint": {"fill-color": "steelblue"},
},
{
"id": "roads",
"source": "example_source",
"source-layer": "roads",
"type": "line",
"paint": {"line-color": "black"},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
m = leafmap.Map()
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "landuse",
"type": "fill",
"paint": {"fill-color": "steelblue"},
},
{
"id": "roads",
"source": "example_source",
"source-layer": "roads",
"type": "line",
"paint": {"line-color": "black"},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
In [5]:
Copied!
m.layer_interact()
m.layer_interact()

Overture data¶
You can also visualize Overture data. Inspired by overture-maps.
In [6]:
Copied!
url = "https://storage.googleapis.com/ahp-research/overture/pmtiles/overture.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
url = "https://storage.googleapis.com/ahp-research/overture/pmtiles/overture.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
layer names: ['admins', 'buildings', 'places', 'roads'] bounds: [3.295898, 50.746884, 7.245483, 53.5762]
In [7]:
Copied!
m = leafmap.Map(height="800px")
m.add_basemap("Esri.WorldImagery")
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
# {
# "id": "admins",
# "source": "example_source",
# "source-layer": "admins",
# "type": "fill",
# "paint": {"fill-color": "#BDD3C7", "fill-opacity": 0.1},
# },
{
"id": "buildings",
"source": "example_source",
"source-layer": "buildings",
"type": "fill",
"paint": {"fill-color": "#FFFFB3", "fill-opacity": 0.5},
},
{
"id": "places",
"source": "example_source",
"source-layer": "places",
"type": "fill",
"paint": {"fill-color": "#BEBADA", "fill-opacity": 0.5},
},
{
"id": "roads",
"source": "example_source",
"source-layer": "roads",
"type": "line",
"paint": {"line-color": "#FB8072"},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
m = leafmap.Map(height="800px")
m.add_basemap("Esri.WorldImagery")
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
# {
# "id": "admins",
# "source": "example_source",
# "source-layer": "admins",
# "type": "fill",
# "paint": {"fill-color": "#BDD3C7", "fill-opacity": 0.1},
# },
{
"id": "buildings",
"source": "example_source",
"source-layer": "buildings",
"type": "fill",
"paint": {"fill-color": "#FFFFB3", "fill-opacity": 0.5},
},
{
"id": "places",
"source": "example_source",
"source-layer": "places",
"type": "fill",
"paint": {"fill-color": "#BEBADA", "fill-opacity": 0.5},
},
{
"id": "roads",
"source": "example_source",
"source-layer": "roads",
"type": "line",
"paint": {"line-color": "#FB8072"},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
In [8]:
Copied!
m.layer_interact()
m.layer_interact()

Source Cooperative¶
In [9]:
Copied!
url = "https://data.source.coop/vida/google-microsoft-open-buildings/pmtiles/go_ms_building_footprints.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
url = "https://data.source.coop/vida/google-microsoft-open-buildings/pmtiles/go_ms_building_footprints.pmtiles"
metadata = leafmap.pmtiles_metadata(url)
print(f"layer names: {metadata['layer_names']}")
print(f"bounds: {metadata['bounds']}")
layer names: ['building_footprints'] bounds: [-160.221701, -55.9756776, 166.709685, 74.7731168]
In [10]:
Copied!
m = leafmap.Map(center=[0, 20], zoom=2, height="800px")
m.add_basemap("Google Hybrid", visible=False)
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "building_footprints",
"type": "fill",
"paint": {"fill-color": "#3388ff", "fill-opacity": 0.5},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
m = leafmap.Map(center=[0, 20], zoom=2, height="800px")
m.add_basemap("Google Hybrid", visible=False)
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "building_footprints",
"type": "fill",
"paint": {"fill-color": "#3388ff", "fill-opacity": 0.5},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=1.0,
tooltip=True,
)
m
Basemap can only be one of the following: OpenStreetMap Esri.WorldStreetMap Esri.WorldImagery Esri.WorldTopoMap FWS NWI Wetlands FWS NWI Wetlands Raster NLCD 2021 CONUS Land Cover NLCD 2019 CONUS Land Cover NLCD 2016 CONUS Land Cover NLCD 2013 CONUS Land Cover NLCD 2011 CONUS Land Cover NLCD 2008 CONUS Land Cover NLCD 2006 CONUS Land Cover NLCD 2004 CONUS Land Cover NLCD 2001 CONUS Land Cover USGS NAIP Imagery USGS NAIP Imagery False Color USGS NAIP Imagery NDVI USGS Hydrography USGS 3DEP Elevation ESA Worldcover 2020 ESA Worldcover 2020 S2 FCC ESA Worldcover 2020 S2 TCC ESA Worldcover 2021 ESA Worldcover 2021 S2 FCC ESA Worldcover 2021 S2 TCC BaseMapDE.Color BaseMapDE.Grey BasemapAT.basemap BasemapAT.grau BasemapAT.highdpi BasemapAT.orthofoto BasemapAT.overlay BasemapAT.surface BasemapAT.terrain CartoDB.DarkMatter CartoDB.DarkMatterNoLabels CartoDB.DarkMatterOnlyLabels CartoDB.Positron CartoDB.PositronNoLabels CartoDB.PositronOnlyLabels CartoDB.Voyager CartoDB.VoyagerLabelsUnder CartoDB.VoyagerNoLabels CartoDB.VoyagerOnlyLabels CyclOSM Esri.AntarcticBasemap Esri.AntarcticImagery Esri.ArcticImagery Esri.ArcticOceanBase Esri.ArcticOceanReference Esri.DeLorme Esri.NatGeoWorldMap Esri.OceanBasemap Esri.WorldGrayCanvas Esri.WorldPhysical Esri.WorldShadedRelief Esri.WorldTerrain FreeMapSK Gaode.Normal Gaode.Satellite HikeBike.HikeBike HikeBike.HillShading JusticeMap.americanIndian JusticeMap.asian JusticeMap.black JusticeMap.hispanic JusticeMap.income JusticeMap.multi JusticeMap.nonWhite JusticeMap.plurality JusticeMap.white MtbMap NASAGIBS.ASTER_GDEM_Greyscale_Shaded_Relief NASAGIBS.BlueMarble3031 NASAGIBS.BlueMarble3413 NASAGIBS.BlueMarbleBathymetry3031 NASAGIBS.BlueMarbleBathymetry3413 NASAGIBS.MEaSUREsIceVelocity3031 NASAGIBS.MEaSUREsIceVelocity3413 NASAGIBS.ModisAquaBands721CR NASAGIBS.ModisAquaTrueColorCR NASAGIBS.ModisTerraAOD NASAGIBS.ModisTerraBands367CR NASAGIBS.ModisTerraBands721CR NASAGIBS.ModisTerraChlorophyll NASAGIBS.ModisTerraLSTDay NASAGIBS.ModisTerraSnowCover NASAGIBS.ModisTerraTrueColorCR NASAGIBS.ViirsEarthAtNight2012 NASAGIBS.ViirsTrueColorCR OPNVKarte OneMapSG.Default OneMapSG.Grey OneMapSG.LandLot OneMapSG.Night OneMapSG.Original OpenAIP OpenFireMap OpenRailwayMap OpenSeaMap OpenSnowMap.pistes OpenStreetMap.BZH OpenStreetMap.BlackAndWhite OpenStreetMap.CH OpenStreetMap.DE OpenStreetMap.HOT OpenStreetMap.Mapnik OpenTopoMap SafeCast Stadia.AlidadeSatellite Stadia.AlidadeSmooth Stadia.AlidadeSmoothDark Stadia.OSMBright Stadia.Outdoors Stadia.StamenTerrain Stadia.StamenTerrainBackground Stadia.StamenTerrainLabels Stadia.StamenTerrainLines Stadia.StamenToner Stadia.StamenTonerBackground Stadia.StamenTonerLabels Stadia.StamenTonerLines Stadia.StamenTonerLite Stadia.StamenWatercolor Strava.All Strava.Ride Strava.Run Strava.Water Strava.Winter SwissFederalGeoportal.JourneyThroughTime SwissFederalGeoportal.NationalMapColor SwissFederalGeoportal.NationalMapGrey SwissFederalGeoportal.SWISSIMAGE TopPlusOpen.Color TopPlusOpen.Grey USGS.USImagery USGS.USImageryTopo USGS.USTopo WaymarkedTrails.cycling WaymarkedTrails.hiking WaymarkedTrails.mtb WaymarkedTrails.riding WaymarkedTrails.skating WaymarkedTrails.slopes nlmaps.grijs nlmaps.luchtfoto nlmaps.pastel nlmaps.standaard nlmaps.water
In [11]:
Copied!
m.layer_interact()
m.layer_interact()

Local PMTiles¶
tippecanoe is required to convert vector data to pmtiles. Install it with conda install -c conda-forge tippecanoe.
Download building footprints of Derna, Libya.
In [12]:
Copied!
url = "https://raw.githubusercontent.com/opengeos/open-data/main/datasets/libya/Derna_buildings.geojson"
leafmap.download_file(url, "buildings.geojson")
url = "https://raw.githubusercontent.com/opengeos/open-data/main/datasets/libya/Derna_buildings.geojson"
leafmap.download_file(url, "buildings.geojson")
buildings.geojson already exists. Skip downloading. Set overwrite=True to overwrite.
Out[12]:
'/home/runner/work/leafmap/leafmap/docs/notebooks/buildings.geojson'
Convert vector to PMTiles.
In [13]:
Copied!
pmtiles = "buildings.pmtiles"
leafmap.geojson_to_pmtiles(
"buildings.geojson", pmtiles, layer_name="buildings", overwrite=True, quiet=True
)
pmtiles = "buildings.pmtiles"
leafmap.geojson_to_pmtiles(
"buildings.geojson", pmtiles, layer_name="buildings", overwrite=True, quiet=True
)
Error: tippecanoe is not installed. You can install it using conda with the following command: conda install -c conda-forge tippecanoe
Start a HTTP Sever
In [14]:
Copied!
leafmap.start_server(port=8000)
leafmap.start_server(port=8000)
In [15]:
Copied!
url = f"http://127.0.0.1:8000/{pmtiles}"
# leafmap.pmtiles_metadata(url)
url = f"http://127.0.0.1:8000/{pmtiles}"
# leafmap.pmtiles_metadata(url)
Display the PMTiles on the map.
In [16]:
Copied!
m = leafmap.Map()
m.add_basemap("Google Hybrid")
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "buildings",
"type": "fill",
"paint": {"fill-color": "#3388ff", "fill-opacity": 0.5},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=0.8,
tooltip=True,
)
m
m = leafmap.Map()
m.add_basemap("Google Hybrid")
style = {
"version": 8,
"sources": {
"example_source": {
"type": "vector",
"url": "pmtiles://" + url,
"attribution": "PMTiles",
}
},
"layers": [
{
"id": "buildings",
"source": "example_source",
"source-layer": "buildings",
"type": "fill",
"paint": {"fill-color": "#3388ff", "fill-opacity": 0.5},
},
],
}
# style = leafmap.pmtiles_style(url) # Use default style
m.add_pmtiles(
url,
style=style,
visible=True,
opacity=0.8,
tooltip=True,
)
m
Basemap can only be one of the following:
OpenStreetMap
Esri.WorldStreetMap
Esri.WorldImagery
Esri.WorldTopoMap
FWS NWI Wetlands
FWS NWI Wetlands Raster
NLCD 2021 CONUS Land Cover
NLCD 2019 CONUS Land Cover
NLCD 2016 CONUS Land Cover
NLCD 2013 CONUS Land Cover
NLCD 2011 CONUS Land Cover
NLCD 2008 CONUS Land Cover
NLCD 2006 CONUS Land Cover
NLCD 2004 CONUS Land Cover
NLCD 2001 CONUS Land Cover
USGS NAIP Imagery
USGS NAIP Imagery False Color
USGS NAIP Imagery NDVI
USGS Hydrography
USGS 3DEP Elevation
ESA Worldcover 2020
ESA Worldcover 2020 S2 FCC
ESA Worldcover 2020 S2 TCC
ESA Worldcover 2021
ESA Worldcover 2021 S2 FCC
ESA Worldcover 2021 S2 TCC
BaseMapDE.Color
BaseMapDE.Grey
BasemapAT.basemap
BasemapAT.grau
BasemapAT.highdpi
BasemapAT.orthofoto
BasemapAT.overlay
BasemapAT.surface
BasemapAT.terrain
CartoDB.DarkMatter
CartoDB.DarkMatterNoLabels
CartoDB.DarkMatterOnlyLabels
CartoDB.Positron
CartoDB.PositronNoLabels
CartoDB.PositronOnlyLabels
CartoDB.Voyager
CartoDB.VoyagerLabelsUnder
CartoDB.VoyagerNoLabels
CartoDB.VoyagerOnlyLabels
CyclOSM
Esri.AntarcticBasemap
Esri.AntarcticImagery
Esri.ArcticImagery
Esri.ArcticOceanBase
Esri.ArcticOceanReference
Esri.DeLorme
Esri.NatGeoWorldMap
Esri.OceanBasemap
Esri.WorldGrayCanvas
Esri.WorldPhysical
Esri.WorldShadedRelief
Esri.WorldTerrain
FreeMapSK
Gaode.Normal
Gaode.Satellite
HikeBike.HikeBike
HikeBike.HillShading
JusticeMap.americanIndian
JusticeMap.asian
JusticeMap.black
JusticeMap.hispanic
JusticeMap.income
JusticeMap.multi
JusticeMap.nonWhite
JusticeMap.plurality
JusticeMap.white
MtbMap
NASAGIBS.ASTER_GDEM_Greyscale_Shaded_Relief
NASAGIBS.BlueMarble3031
NASAGIBS.BlueMarble3413
NASAGIBS.BlueMarbleBathymetry3031
NASAGIBS.BlueMarbleBathymetry3413
NASAGIBS.MEaSUREsIceVelocity3031
NASAGIBS.MEaSUREsIceVelocity3413
NASAGIBS.ModisAquaBands721CR
NASAGIBS.ModisAquaTrueColorCR
NASAGIBS.ModisTerraAOD
NASAGIBS.ModisTerraBands367CR
NASAGIBS.ModisTerraBands721CR
NASAGIBS.ModisTerraChlorophyll
NASAGIBS.ModisTerraLSTDay
NASAGIBS.ModisTerraSnowCover
NASAGIBS.ModisTerraTrueColorCR
NASAGIBS.ViirsEarthAtNight2012
NASAGIBS.ViirsTrueColorCR
OPNVKarte
OneMapSG.Default
OneMapSG.Grey
OneMapSG.LandLot
OneMapSG.Night
OneMapSG.Original
OpenAIP
OpenFireMap
OpenRailwayMap
OpenSeaMap
OpenSnowMap.pistes
OpenStreetMap.BZH
OpenStreetMap.BlackAndWhite
OpenStreetMap.CH
OpenStreetMap.DE
OpenStreetMap.HOT
OpenStreetMap.Mapnik
OpenTopoMap
SafeCast
Stadia.AlidadeSatellite
Stadia.AlidadeSmooth
Stadia.AlidadeSmoothDark
Stadia.OSMBright
Stadia.Outdoors
Stadia.StamenTerrain
Stadia.StamenTerrainBackground
Stadia.StamenTerrainLabels
Stadia.StamenTerrainLines
Stadia.StamenToner
Stadia.StamenTonerBackground
Stadia.StamenTonerLabels
Stadia.StamenTonerLines
Stadia.StamenTonerLite
Stadia.StamenWatercolor
Strava.All
Strava.Ride
Strava.Run
Strava.Water
Strava.Winter
SwissFederalGeoportal.JourneyThroughTime
SwissFederalGeoportal.NationalMapColor
SwissFederalGeoportal.NationalMapGrey
SwissFederalGeoportal.SWISSIMAGE
TopPlusOpen.Color
TopPlusOpen.Grey
USGS.USImagery
USGS.USImageryTopo
USGS.USTopo
WaymarkedTrails.cycling
WaymarkedTrails.hiking
WaymarkedTrails.mtb
WaymarkedTrails.riding
WaymarkedTrails.skating
WaymarkedTrails.slopes
nlmaps.grijs
nlmaps.luchtfoto
nlmaps.pastel
nlmaps.standaard
nlmaps.water
HTTPConnectionPool(host='127.0.0.1', port=8000): Max retries exceeded with url: /buildings.pmtiles (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7ce4979350>: Failed to establish a new connection: [Errno 111] Connection refused'))
In [17]:
Copied!
m.layer_interact()
m.layer_interact()
